package cn.tanghom.support.page;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.springframework.core.convert.converter.Converter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;

/**
 * 分页类
 *
 * @param <T> 分页数据的类型
 * @author DongQihong
 */
public class Pager<T> implements Page<T>,Serializable {
	
	protected List<T> content;
	protected Pageable pageable;	
	/**
     * 当前页
     */
    protected int index = 1;
    
    /**
     * 每页大小
     */
    protected int size = 10;
    /**
     * 总记录数
     */
    protected long totalRecord = 0L;
    

    
    public Pager(){    	
    	content = new ArrayList<T>();
    }
    
    public Pager(List<T> items){    	
    	this.content = items;
    	totalRecord =(long) items.size();
    }
    
    public Pager(Integer page, Integer pageSize){
		this.index = page==null? 1:page.intValue();
		this.size = pageSize==null? 10:pageSize;
	}
	

	/**
	 * Creates a new {@link Pager} with the given content and the given governing {@link Pageable}.
	 * 
	 * @param content must not be {@literal null}.
	 * @param pageable can be {@literal null}.
	 */
	public Pager(List<T> content, Pageable pageable, long total) {

		Assert.notNull(content, "Content must not be null!");

		this.content.addAll(content);
		this.pageable = pageable;
		this.totalRecord = total;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#getNumber()
	 */
	public int getNumber() {
		return pageable == null ? index : pageable.getPageNumber();
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#getSize()
	 */
	public int getSize() {
		return pageable == null ? size : pageable.getPageSize();
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#getNumberOfElements()
	 */
	public int getNumberOfElements() {
		return content.size();
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#hasPrevious()
	 */
	public boolean hasPrevious() {
		return getNumber() > 0;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#isFirst()
	 */
	public boolean isFirst() {
		return !hasPrevious();
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#isLast()
	 */
	public boolean isLast() {
		return !hasNext();
	}

	/* 
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#nextPageable()
	 */
	public Pageable nextPageable() {
		return hasNext() ? pageable.next() : null;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#previousPageable()
	 */
	public Pageable previousPageable() {

		if (hasPrevious()) {
			return pageable.previousOrFirst();
		}

		return null;
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#hasContent()
	 */
	public boolean hasContent() {
		return !content.isEmpty();
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#getContent()
	 */
	public List<T> getContent() {
		return Collections.unmodifiableList(content);
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#getSort()
	 */
	public Sort getSort() {
		return pageable == null ? null : pageable.getSort();
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Iterable#iterator()
	 */
	public Iterator<T> iterator() {
		return content.iterator();
	}

	/**
	 * Applies the given {@link Converter} to the content of the {@link Pager}.
	 * 
	 * @param converter must not be {@literal null}.
	 * @return
	 */
	protected <S> List<S> getConvertedContent(Converter<? super T, ? extends S> converter) {

		Assert.notNull(converter, "Converter must not be null!");

		List<S> result = new ArrayList<S>(content.size());

		for (T element : this) {
			result.add(converter.convert(element));
		}

		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {

		if (this == obj) {
			return true;
		}

		if (!(obj instanceof Pager<?>)) {
			return false;
		}

		Pager<?> that = (Pager<?>) obj;

		boolean contentEqual = this.content.equals(that.content);
		boolean pageableEqual = this.pageable == null ? that.pageable == null : this.pageable.equals(that.pageable);

		return contentEqual && pageableEqual;
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {

		int result = 17;

		result += 31 * (pageable == null ? 0 : pageable.hashCode());
		result += 31 * content.hashCode();

		return result;
	}
    /**
     * 获取数据
     *
     * @return 数据
     */
    public List<T> getItems() {
        return content;
    }

    /**
     * 设置数据
     *
     * @param items 分页数据项
     */
    public void setItems(List<T> items) {
        this.content = items;
    }

    /**
     * 获取当前页码
     *
     * @return 当前页码
     */
    public Long getIndex() {
        return Long.valueOf(index);
    }

    /**
     * 设置当前页码
     *
     * @param index 当前页码
     */
    public void setIndex(Long index) {
    	if(index!=null){
    		this.index = index.intValue();
    		if(this.index<=0) this.index=1;
    	}
    	else{
    		this.index=1;
    	}
    }
   

    /**
     * 设置每页多少条
     *
     * @param size 每页多少条
     */
    public void setSize(int size) {       
        this.size = size;
    }

    /**
     * 获取总记录数
     *
     * @return 总记录数
     */
    public Long getTotalRecord() {
        return totalRecord;
    }

    /**
     * 设置总记录数
     *
     * @param count 总记录数
     */
    public void setTotalRecord(Long count) {
        this.totalRecord = (null == count) ? 0 : count;       
    }
    
    public void setTotal(long count) {
        this.totalRecord = count;       
    }


    /**
     * 计算当前页开始记录
     *
     * @return 开始记录
     */
    public Long startRow() {
        final long firstResult = size * (index - 1);
        return firstResult;
    }
    
    public int getCurrent() {
		return index;
	}
	
	public int getRowCount() {
		return getSize();
	}
    
	public void setCurrent(int page) {
        this.index = page;
    }	
	
    public void setRowCount(int size) {
       this.setSize(size);
    }	
	 
	/**
	 * 计算分页,返回[offset,limit]
	 * @param total
	 * @return
	 */
	public int[] getPageParams(Integer total) {
		if(this.index < 1){
			this.index = 1;
		}
		if(this.size < 1){
			this.size = 10;
		}
		long firstResult = (this.index - 1L) * this.size;
		int maxResult = this.size;
		
		//校验分页情况
		if (firstResult >= total || firstResult < 0) {
			firstResult = 0;
			this.index = 1;
		}
		return new int[]{(int)firstResult, maxResult};
	}

    public Pageable getPageable() {
		return pageable;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Page#getTotalPages()
	 */
	@Override
	public int getTotalPages() {
		return getSize() == 0 ? 1 : (int) Math.ceil((double) totalRecord / (double) getSize());
	}

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Page#getTotalElements()
	 */
	@Override
	public long getTotalElements() {
		return totalRecord;
	}

	public long getTotal() {
		return totalRecord;
	}
	
	/* 
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#hasNext()
	 */
	@Override
	public boolean hasNext() {
		return getNumber() + 1 < getTotalPages();
	}

	

	/* 
	 * (non-Javadoc)
	 * @see org.springframework.data.domain.Slice#transform(org.springframework.core.convert.converter.Converter)
	 */
	@Override
	public <S> Pager<S> map(Converter<? super T, ? extends S> converter) {
		return new Pager<S>(getConvertedContent(converter), pageable, totalRecord);
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {

		String contentType = "UNKNOWN";
		List<T> content = getContent();

		if (content.size() > 0) {
			contentType = content.get(0).getClass().getName();
		}

		return String.format("Page %s of %d containing %s instances", getNumber() + 1, getTotalPages(), contentType);
	}
}
